use async_graphql::{Request, Response};
use linera_sdk::{
    abi::{ContractAbi, ServiceAbi},
    abis::fungible::Account,
    graphql::GraphQLMutationRoot,
    linera_base_types::AccountOwner,
    DataBlobHash,
};
use serde::{Deserialize, Serialize};

mod nft;
pub use nft::*;

pub struct NonFungibleTokenAbi;

impl ContractAbi for NonFungibleTokenAbi {
    type Operation = Operation;
    type Response = ();
}

impl ServiceAbi for NonFungibleTokenAbi {
    type Query = Request;
    type QueryResponse = Response;
}

/// An operation
#[derive(Debug, Deserialize, Serialize, GraphQLMutationRoot)]
pub enum Operation {
    /// Mints a token
    Mint {
        minter: AccountOwner,
        name: String,
        blob_hash: DataBlobHash,
    },
    /// Transfers a token from a (locally owned) account to a (possibly remote)
    /// account
    Transfer {
        source_owner: AccountOwner,
        token_id: TokenId,
        target_account: Account,
    },
    /// Same as `Transfer` but the source account may be remote. Depending on
    /// its configuration, the target chain may take time or refuse to process
    /// the message.
    Claim {
        source_account: Account,
        token_id: TokenId,
        target_account: Account,
    },
}

/// A message
#[derive(Debug, Deserialize, Serialize)]
pub enum Message {
    /// Transfers to the given `target` account, unless the message is bouncing,
    /// in which case we transfer back to the `source`.
    Transfer { nft: Nft, target_account: Account },
    /// Claims from the given account and starts a transfer to the target account
    Claim {
        source_account: Account,
        token_id: TokenId,
        target_account: Account,
    },
}
